﻿using GalaSoft.MvvmLight.Messaging;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

namespace AirQuality
{
    public class Server
    {
        public static SerialPort serialPort = new SerialPort() { NewLine = "BM", BaudRate = 9600, Parity = Parity.None, DataBits = 8, StopBits = StopBits.One, ReadTimeout = 2000 };

        public static PMSensor pMSensors = new PMSensor();

        public static bool IsSetting = false;

        public static List<PMSensor> _Buffer = new List<PMSensor>(10);

        public static JObject ConfigJson;
        //串口读取线程
        public static Thread SerialThread = new Thread(SerialEncode)
        {
            IsBackground = true
        };

        //窗口滤波
        private static void Filter()
        {
            PMSensor sensor = new PMSensor(pMSensors);
            if (_Buffer.Count != 0)
            {
                foreach (PMSensor item in _Buffer)
                {
                    pMSensors += item;
                }
                pMSensors /= _Buffer.Count + 1;
            }
            _Buffer.Add(sensor);

            //Console.WriteLine("buffer count={0}",_Buffer.Count);
            if (_Buffer.Count >= _Buffer.Capacity)
            {
                _Buffer.RemoveAt(0);
            }
        }

        //串口读取数据解码函数
        public static void SerialEncode()
        {
            byte[] serialData = new byte[32];
            serialData[0] = 0x42;
            serialData[1] = 0x4d;
            while (true)
            {
                while (serialPort.IsOpen)
                {
                    try
                    {
                        char[] receiverData = serialPort.ReadLine().ToCharArray();
                        for (int i = 0; i < receiverData.Length; i++)
                        {
                            serialData[i + 2] = Convert.ToByte(receiverData[i]);
                        }
                        //Console.WriteLine("receiver data length {0}",receiverData.Length);
                        if (serialData[2] == 0x00 && serialData[3] == 0x1c)
                        {
                            int check = 0;
                            for (int i = 0; i < 30; i++)
                            {
                                check += serialData[i];
                            }
                            //Console.WriteLine(check);
                            //Console.WriteLine(serialData[30] * 256 + serialData[31]);
                            //Console.WriteLine("");
                            //if (check == (serialData[30] * 256) + serialData[31])//校验成功
                            {
                                pMSensors.PM1_0 = (serialData[4] * 256) + serialData[5];
                                pMSensors.PM2_5 = (serialData[6] * 256) + serialData[7];
                                pMSensors.PM10 = (serialData[8] * 256) + serialData[9];
                                //Console.WriteLine("PM1.0={0},PM2.5={1},PM10={2}",pMSensors.PM1_0, pMSensors.PM2_5, pMSensors.PM10);
                                pMSensors.PM1_0_air = (serialData[10] * 256) + serialData[11];
                                pMSensors.PM2_5_air = (serialData[12] * 256) + serialData[13];
                                pMSensors.PM10_air = (serialData[14] * 256) + serialData[15];
                                pMSensors.PM0_3_count = (serialData[16] * 256) + serialData[17];
                                pMSensors.PM0_5_count = (serialData[18] * 256) + serialData[19];
                                pMSensors.PM1_0_count = (serialData[20] * 256) + serialData[21];
                                pMSensors.PM2_5_count = (serialData[22] * 256) + serialData[23];
                                pMSensors.PM5_0_count = (serialData[24] * 256) + serialData[25];
                                pMSensors.PM10_count = (serialData[26] * 256) + serialData[27];
                                Filter();
                                Messenger.Default.Send(true, "DataUpdate");
                            }
                            //else
                            //{
                            //    foreach (var item in serialData)
                            //    {
                            //        Console.WriteLine(item);
                            //    }
                            //}
                        }
                    }
                    catch (TimeoutException) { }
                    catch (IOException)
                    {
                        Messenger.Default.Send(false, "SerialERR");
                    }
                    catch (UnauthorizedAccessException)
                    {
                        Messenger.Default.Send(false, "SerialERR");
                    }
                    catch (Exception) { }
                }
                Thread.Sleep(2000);
                if (IsSetting == false)
                {
                    string[] vs = SerialPort.GetPortNames();
                    foreach (string item in vs)
                    {
                        if (item.CompareTo(serialPort.PortName) == 0)
                        {
                            //Console.WriteLine("try open");
                            if (!serialPort.IsOpen)
                            {
                                try
                                {
                                    serialPort.Open();
                                    Messenger.Default.Send(true, "SerialERR");
                                }
                                catch (IOException)
                                {
                                    Messenger.Default.Send(false, "SerialERR");
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
        }

        //read config file and set programmer from the file
        public static void SetFromFile()
        {
            while (true)
            {
                try
                {
                    using (StreamReader streamReader = new StreamReader("config.json"))
                    {
                        ConfigJson = JObject.Parse(streamReader.ReadToEnd());
                        streamReader.Close();
                        break;
                    }
                }
                catch (FileNotFoundException)
                {
                    try
                    {
                        _ = Process.Start("AdminCreatFile.exe",
                                       @"""config.json"" ""{'location':'LeftTop','x':'','y':'','COM':''}""");
                        Thread.Sleep(1000);
                    }
                    catch { }
                }
                catch { }
            }
        }

        //save config
        public static void SaveConfigToFile()
        {
            while (true)
            {
                try
                {
                    using (StreamWriter streamWriter = new StreamWriter("config.json"))
                    {
                        streamWriter.WriteLine(ConfigJson.ToString());
                        streamWriter.Close();
                        break;
                    }
                }
                catch (FileNotFoundException)
                {
                    try
                    {
                        _ = Process.Start("AdminCreatFile.exe",
                                       @"""config.json"" ""''""");
                        Thread.Sleep(1000);
                    }
                    catch { }
                }
                catch { }
            }
        }
    }

    public class PMSensor
    {
        public PMSensor(PMSensor b)
        {
            PM1_0 = b.PM1_0;
            PM2_5 = b.PM2_5;
            PM10 = b.PM10;
            PM1_0_air = b.PM1_0_air;
            PM2_5_air = b.PM2_5_air;
            PM10_air = b.PM10_air;
            PM0_3_count = b.PM0_3_count;
            PM0_5_count = b.PM0_5_count;
            PM1_0_count = b.PM1_0_count;
            PM2_5_count = b.PM2_5_count;
            PM5_0_count = b.PM5_0_count;
            PM10_count = b.PM10_count;
        }

        public PMSensor() { }

        public int PM1_0 { get; set; }
        public int PM2_5 { get; set; }
        public int PM10 { get; set; }
        public int PM1_0_air { get; set; }
        public int PM2_5_air { get; set; }
        public int PM10_air { get; set; }
        public int PM0_3_count { get; set; }
        public int PM0_5_count { get; set; }
        public int PM1_0_count { get; set; }
        public int PM2_5_count { get; set; }
        public int PM5_0_count { get; set; }
        public int PM10_count { get; set; }

        public static PMSensor operator +(PMSensor a, PMSensor b)
        {
            a.PM1_0 += b.PM1_0;
            a.PM2_5 += b.PM2_5;
            a.PM10 += b.PM10;
            a.PM1_0_air += b.PM1_0_air;
            a.PM2_5_air += b.PM2_5_air;
            a.PM10_air += b.PM10_air;
            a.PM0_3_count += b.PM0_3_count;
            a.PM0_5_count += b.PM0_5_count;
            a.PM1_0_count += b.PM1_0_count;
            a.PM2_5_count += b.PM2_5_count;
            a.PM5_0_count += b.PM5_0_count;
            a.PM10_count += b.PM10_count;
            return a;
        }

        public static PMSensor operator /(PMSensor a, int b)
        {
            a.PM1_0 /= b;
            a.PM2_5 /= b;
            a.PM10 /= b;
            a.PM1_0_air /= b;
            a.PM2_5_air /= b;
            a.PM10_air /= b;
            a.PM0_3_count /= b;
            a.PM0_5_count /= b;
            a.PM1_0_count /= b;
            a.PM2_5_count /= b;
            a.PM5_0_count /= b;
            a.PM10_count /= b;
            return a;
        }
    }
}
